/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.nuanshui.heatedloan.search.biz;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import org.apache.lucene.index.Term;
import org.apache.lucene.queries.TermsQuery;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetRequestBuilder;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.CommonTermsQueryBuilder;
import org.elasticsearch.index.query.DisMaxQueryBuilder;
import org.elasticsearch.index.query.HasChildQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.fieldvaluefactor.FieldValueFactorFunctionBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;
import com.nuanshui.heatedloan.search.base.enums.SearchParamType;
import com.nuanshui.heatedloan.search.facade.ElasticSearchService;
import com.nuanshui.heatedloan.search.facade.model.ElasticSearchRequest;
import com.nuanshui.heatedloan.search.facade.model.ElasticSearchResponse;
import com.nuanshui.heatedloan.search.facade.model.ElasticSearchUtil;
import com.nuanshui.heatedloan.search.facade.model.FieldValueFactor;
import com.nuanshui.heatedloan.search.facade.model.SearchParams;
import org.springframework.stereotype.Service;

/**
 *
 * @author Uttesh Kumar T.H.
 */
@Service("ElasticSearchService")
public class ElasticSearchServiceImpl  implements ElasticSearchService{

    private static final Logger logger = LoggerFactory.getLogger(ElasticSearchServiceImpl.class);

    private static ElasticSearchServiceImpl instance = null;

    public static ElasticSearchServiceImpl getInstance() {
        if (instance == null) {
            instance = new ElasticSearchServiceImpl();
        }
        return instance;
    }

    public ElasticSearchServiceImpl()
	{
		ElasticSearchUtil.getClient();
	}

	@Override
	public String test()
	{
		return "test";
	}

    @Override
	public boolean isIndexExist(String id) {
        try {
            if (ElasticSearchUtil.getClient().admin().indices().prepareExists(id).execute().actionGet().isExists()) {
                return true;
            }
        } catch (Exception exception) {
            logger.error("isIndexExist: index error", exception);
        }

        return false;
    }

    @SuppressWarnings("unused")
	@Override
	public String createIndex(String index, String type, String id, String jsonData) {
        IndexResponse response = null;
        try {
            response = ElasticSearchUtil.getClient().prepareIndex(index, type, id)
                    .setSource(jsonData)
                    .get();
           
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
   

    @Override
	public UpdateResponse updateIndex(String index, String type, String id, String jsonData) {
        UpdateResponse response = null;
        try {
            response = ElasticSearchUtil.getClient().prepareUpdate(index, type, id)
                    .setDoc(jsonData)
                    .execute().get();
            return response;
        } catch (Exception e) {
            logger.error("UpdateIndex", e);
        }
        return null;
    }

    @SuppressWarnings("unused")
	@Override
	public boolean removeDocument(String index, String type, String id) {
        DeleteResponse response = null;
        try {
            response = ElasticSearchUtil.getClient().prepareDelete(index, type, id).execute().actionGet();
            return true;
        } catch (Exception e) {
        	e.printStackTrace();
            logger.error("RemoveIndex", e);
        }
        return false;
    }

    @Override
	public MultiGetResponse findByMultipleIndexs(List<ElasticSearchRequest> requests) {
        try {
            MultiGetRequestBuilder builder = ElasticSearchUtil.getClient().prepareMultiGet();
            for (ElasticSearchRequest _request : requests) {
                builder.add(_request.getIndex(), _request.getType(), _request.getId());
            }
            return builder.get();
        } catch (Exception e) {
            logger.error("findByMultipleIndexs", e);
        }
        return null;
    }

    @Override
	public List<String> getAlldata(MultiGetResponse multiGetResponse) {
        List<String> data = new ArrayList<String>();
        try {
            for (MultiGetItemResponse itemResponse : multiGetResponse) {
                GetResponse response = itemResponse.getResponse();
                if (response.isExists()) {
                    String json = response.getSourceAsString();
                    data.add(json);
                }
            }
            return data;
        } catch (Exception e) {
            logger.error("", e);
        }
        return null;
    }

    @Override
	public GetResponse findDocumentByIndex(String index, String type, String id) {
        try {
            GetResponse getResponse = ElasticSearchUtil.getClient().prepareGet(index, type, id).get();
            return getResponse;
        } catch (Exception e) {
            logger.error("", e);
        }
        return null;
    }

    @SuppressWarnings("unused")
	@Override
	public SearchResponse findDocument(String index, String type, String field, String value) {
        try {
            QueryBuilder queryBuilder = new MatchQueryBuilder(field, value);
            SearchResponse response = ElasticSearchUtil.getClient().prepareSearch(index)
                    .setTypes(type)
                    .setSearchType(SearchType.QUERY_AND_FETCH)
                    .setQuery(queryBuilder)
                    .addHighlightedField("des")
                    .addHighlightedField("FirstName")
                    .setHighlighterPreTags("<span style=\"color:red\">")
                    .setHighlighterPostTags("</span>")
                    .setFrom(0).setSize(60).setExplain(true)
                    .execute()
                    .actionGet();
            SearchHit[] results = response.getHits().getHits();
            return response;
        } catch (Exception e) {
            logger.error("", e);
        }
        return null;
    }

    
    
	@Override
	public ElasticSearchResponse findDocumentStr(String index, String type,HashMap<String,String> params) {
		 try {
			    ElasticSearchResponse elasticSearchResponse = new ElasticSearchResponse();
	            QueryBuilder queryBuilder  = getQuery(params);
	            SearchResponse response = ElasticSearchUtil.getClient().prepareSearch(index)
	                    .setTypes(type)
	                    .setSearchType(SearchType.QUERY_THEN_FETCH)
	                    .setQuery(queryBuilder)
	                    .addHighlightedField("des")
	                    .addHighlightedField("nick")
	                    .setHighlighterPreTags("<span style=\"color:red\">")
	                    .setHighlighterPostTags("</span>")
	                    .setFrom(1).setSize(2).setExplain(false)
	                    .execute()
	                    .actionGet();
	            
	            elasticSearchResponse.setTotal(response.getHits().getTotalHits());
	            SearchHit[] results = response.getHits().hits(); 
	            System.out.println(results.length);
	            List<String> list = new ArrayList<String>();
	            for(SearchHit hit :results) {
	            	list.add(hit.getSourceAsString());
	            }
	            elasticSearchResponse.setData(list);
	            return elasticSearchResponse;
	        } catch (Exception e) {
	            logger.error("", e);
	        }
		return null;
	}
	
	@Override
	public ElasticSearchResponse findDocument(ElasticSearchRequest request) {
		ElasticSearchResponse elasticSearchResponse = new ElasticSearchResponse();
        QueryBuilder queryBuilder  = getSearchParams(request);
        
        SearchRequestBuilder requestBuilder   = ElasticSearchUtil.getClient().prepareSearch(request.getIndex())
                .setTypes(request.getType())
                .setSearchType(SearchType.QUERY_THEN_FETCH)
                .setQuery(queryBuilder);                
        setHighLineField(request, requestBuilder);    
        setSortField(request, requestBuilder);
        setPagerParams(request, requestBuilder);
        SearchResponse response =   requestBuilder.execute().actionGet();
        elasticSearchResponse.setTotal(response.getHits().getTotalHits());
        
        SearchHit[] results = response.getHits().getHits(); 
        List<String> list = new ArrayList<String>();
        for(SearchHit hit :results) {
        	list.add(hit.getSourceAsString());
        }
        elasticSearchResponse.setData(list);
        
        printResult(response);
		return elasticSearchResponse;
	}
	private QueryBuilder getQuery(HashMap<String,String> params) {
        BoolQueryBuilder boolQueryBuilder  = QueryBuilders.boolQuery();
		for(Entry<String, String> e : params.entrySet()) {
            QueryBuilder queryBuilder = new MatchQueryBuilder(e.getKey(),e.getValue());
            boolQueryBuilder.should(queryBuilder);
        }
		return boolQueryBuilder;
	}
	
	private void setHighLineField(ElasticSearchRequest request,SearchRequestBuilder requestBuilder) {
		for(String str:request.getHighLineFileds()) {
			requestBuilder.addHighlightedField(str);
		}
		requestBuilder.setHighlighterPreTags("<span style=\"color:red\">").setHighlighterPostTags("</span>");	
	}
	
	
	private void setSortField(ElasticSearchRequest request,SearchRequestBuilder requestBuilder) {
		for(Entry<String, Integer> entry :request.getSortFileds().entrySet()){
			Integer sortType = entry.getValue();
			if(sortType == ElasticSearchRequest.ORDER_DIRECTION_ASC) {
				requestBuilder.addSort(entry.getKey(),SortOrder.ASC);
			}else if(sortType == ElasticSearchRequest.ORDER_DIRECTION_DESC) {
				requestBuilder.addSort(entry.getKey(),SortOrder.DESC);
			}else {
				
			}
		}
 	}
	
	
	private static  QueryBuilder getSearchParams(ElasticSearchRequest request) {
		
		BoolQueryBuilder  boolQueryBuilder =  QueryBuilders.boolQuery();
		
		List<SearchParams> searchParams =  request.getSearchParams();
		for(SearchParams param :searchParams) {
			if(param.getFields().size()<=0) continue;
			Iterator<String> iterator =  param.getFields().keySet().iterator();
	        String field = iterator.next();
	        float boost = Float.valueOf(param.getFields().get(field)+"");
			switch (param.getSearchType()) {
			case TERM:
		        
		        TermQueryBuilder termQueryBuilder =   QueryBuilders.termQuery(field,param.getValue());
                if(boost>0) {
                	termQueryBuilder.boost(boost);
                }
                boolQueryBuilder.must(termQueryBuilder);
				break;
            case LT:
				 RangeQueryBuilder rangeQueryBuilder =  QueryBuilders.rangeQuery(field).lt(Double.valueOf(param.getValue()));
				 if(boost>0) {
	                	rangeQueryBuilder.boost(boost);
	                }
	                boolQueryBuilder.must(rangeQueryBuilder);

				break;
            case LTE:
            	 RangeQueryBuilder lteQueryBuilder =  QueryBuilders.rangeQuery(field).lte(Double.valueOf(param.getValue()));
				 if(boost>0) {
					 lteQueryBuilder.boost(boost);
	                }
	                boolQueryBuilder.must(lteQueryBuilder);

	          break;
            case GTE:
            	
            	RangeQueryBuilder gteQueryBuilder =  QueryBuilders.rangeQuery(field).gte(Double.valueOf(param.getValue()));
				 if(boost>0) {
					 gteQueryBuilder.boost(boost);
	                }
	                boolQueryBuilder.must(gteQueryBuilder);

	         break;
	         
            case GT :
            	RangeQueryBuilder gtQueryBuilder =  QueryBuilders.rangeQuery(field).gte(Double.valueOf(param.getValue()));
				 if(boost>0) {
					 gtQueryBuilder.boost(boost);
	                }
	                boolQueryBuilder.must(gtQueryBuilder);
            	break;
	         case MATCH:
	   		  MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(field,param.getValue());
	   		  if(boost>0) {
	   			matchQueryBuilder.boost(boost);
               }
                boolQueryBuilder.must(matchQueryBuilder);
	          break;
	         case MATCH_PHRASE:
	        	 MatchQueryBuilder matchPhraseQueryBuilder = QueryBuilders.matchPhraseQuery(field,param.getValue());
		   		  if(boost>0) {
		   			matchPhraseQueryBuilder.boost(boost);
	               }
	                boolQueryBuilder.must(matchPhraseQueryBuilder);
	        	 
	        	 break;
	         case MULTI_MATCH:
	             MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(param.getValue());
	             
			      if(boost>0) {
			    	  multiMatchQueryBuilder.field(field, boost);
			      }else {
			    	  multiMatchQueryBuilder.field(field);
			      } 
	             do{
	            	 field = iterator.next();
				      boost = Float.valueOf(param.getFields().get(field)+"");
				      if(boost>0) {
				    	  multiMatchQueryBuilder.field(field, boost);
				      }else {
				    	  multiMatchQueryBuilder.field(field);
				      } 
				     
	             }while(iterator.hasNext());
	             boolQueryBuilder.must(multiMatchQueryBuilder);
	        	 break;

			default:
				break;
			}
		}
		
		
		
	    FieldValueFactor fieldValueFactor =  request.getFieldValueFactor();
	    if(fieldValueFactor!=null) {//进行加分字段处理
	         FunctionScoreQueryBuilder functionScoreQueryBuilder  =    QueryBuilders.functionScoreQuery(boolQueryBuilder);
	    	 FieldValueFactorFunctionBuilder fieldValueFactorFunctionBuilder =  new FieldValueFactorFunctionBuilder(fieldValueFactor.getField());
	         fieldValueFactorFunctionBuilder.setWeight(fieldValueFactor.getWeight());
	         fieldValueFactorFunctionBuilder.missing(fieldValueFactor.getMissing());
	         if(fieldValueFactor.getFactor()!=null) {
	        	 fieldValueFactorFunctionBuilder.factor(fieldValueFactor.getFactor());
	         }
	         functionScoreQueryBuilder.add(fieldValueFactorFunctionBuilder); 
	         return functionScoreQueryBuilder;
	    	
	    }
		
		return boolQueryBuilder;
		
		
	}
	private void setPagerParams(ElasticSearchRequest request,SearchRequestBuilder requestBuilder) {
	
		requestBuilder.setFrom(request.getOffset()).setSize(request.getSize()).setExplain(false);
	}
	
	
	
	@SuppressWarnings("unused")
	private void sleep(long m){
		try {
			Thread.sleep(m);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	@SuppressWarnings("unused")
	public static void main(String[] args) throws Exception{
		
		
		 
		
		  MatchQueryBuilder query = QueryBuilders.matchQuery("goodsAttr.title", "1.7cm");
		  query.boost(2);
		  MatchQueryBuilder quer2 = QueryBuilders.matchQuery("userId", "1wnvi");

		  MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
		  //query.operator(Operator.OR);
		 QueryBuilder queryBuilder  = new CommonTermsQueryBuilder("title","贝勒爷");
         TermsQuery termsQuery = new TermsQuery(new Term("title","和田玉"));	
         
         
         
         RangeQueryBuilder rangeQueryBuilder =  QueryBuilders.rangeQuery("sex").lt(1);
        
         
         
         DisMaxQueryBuilder disMaxQueryBuilder =  QueryBuilders.disMaxQuery();
         disMaxQueryBuilder.add(query);
         disMaxQueryBuilder.add(quer2);
         disMaxQueryBuilder.tieBreaker(0.3f);
         
         BoolQueryBuilder  boolQueryBuilder =  QueryBuilders.boolQuery();
         
         
         MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("和田玉", "title");
         multiMatchQueryBuilder.field("typeName",3);
         multiMatchQueryBuilder.field("attrValues",1);
         multiMatchQueryBuilder.field("title", 10);
        
         MatchQueryBuilder attrQuery = QueryBuilders.matchQuery("mkgq", "1.7cm");
         
         HasChildQueryBuilder childQueryBuilder =  QueryBuilders.hasChildQuery("goodsAttr", attrQuery);
         
       //  termsQueryBuilder =   QueryBuilders.termQuery("typeId", "1");
          
         //TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("typeStrId", "b8qp");
         
         TermQueryBuilder termsQueryBuilder =   QueryBuilders.termQuery("userId", "1wnvi");
         termsQueryBuilder.boost(20);
        
		   quer2 = QueryBuilders.matchPhraseQuery("goodsAttr.xptv", "籽料");
		   

          boolQueryBuilder.must(multiMatchQueryBuilder).must(quer2);
          
         
         
         QueryBuilder boolQueryBuilder2 = getSearchParams(getElasticSearchRequest());
         FunctionScoreQueryBuilder functionScoreQueryBuilder  =    QueryBuilders.functionScoreQuery(multiMatchQueryBuilder);
         FieldValueFactorFunctionBuilder fieldValueFactorFunctionBuilder =  new FieldValueFactorFunctionBuilder("activityPost");
         fieldValueFactorFunctionBuilder.setWeight(1);
         fieldValueFactorFunctionBuilder.missing(1.0);
         functionScoreQueryBuilder.add(fieldValueFactorFunctionBuilder);  
         SearchRequestBuilder requestBuilder   = ElasticSearchUtil.getClient().prepareSearch("logs")
	                .setTypes("job_log")
	                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
	                .setQuery(QueryBuilders.termQuery("jobCode", "7145294301511109779824"));
         
	        
	        requestBuilder.setFrom(0).setSize(100);
	       // requestBuilder.setPostFilter(functionScoreQueryBuilder);
	        SearchResponse response =  requestBuilder.execute().get();
	       
	        printResult(response);
	        
	        createMapping();
	        
	        
	}
	
	
	private static  ElasticSearchRequest getElasticSearchRequest() {
		ElasticSearchRequest request = new ElasticSearchRequest();
		
		
		List<SearchParams> searchParams = Lists.newArrayList();
		
		SearchParams param1 = new SearchParams();
		param1.setSearchType(SearchParamType.MULTI_MATCH);
		param1.setValue("这个是玛瑙");
		param1.addField("title",5);
		param1.addField("typeName",3);
		param1.addField("attrValues",10);
			
		searchParams.add(param1);
		
		
		SearchParams param2 = new SearchParams();
        param2.setSearchType(SearchParamType.MATCH);
        param2.setValue("新疆和田");
        param2.addField("goodsAttr.b8qp");
        
        searchParams.add(param2);
        
        
        SearchParams param3 = new SearchParams();
        param3.setSearchType(SearchParamType.TERM);
        param3.setValue("b8qp");
        param3.addField("typeStrId");
        
        searchParams.add(param3);
        
        
        
        SearchParams param4 = new SearchParams();
        param4.setSearchType(SearchParamType.GT);
        param4.setValue("100");
        param4.addField("price");        
        searchParams.add(param4);
        request.setSearchParams(searchParams);
        
		return request;
		
		
		
		
		
		
		
		
	}
	public static void printResult( SearchResponse response) {
		   SearchHits searchHits  = response.getHits();
	       
	       long count = searchHits.getTotalHits();
	       
	       System.out.println("count   "+count);
	       SearchHit hits[] = searchHits.getHits();
	       
	       for(SearchHit hit :hits) {
	    	  System.out.println(hit.getSource().get("activityPost")+" "+hit.getId()+"  "+ hit.getScore()+" ------  "+hit.getSource().get("title")+"   :    "+hit.getSource().get("typeId")+"   "+hit.getSource().get("typeStrId")+"   "+hit.getSource().get("typeName")+"  【"+hit.getSource().get("attrValues")+"】" +"  "+hit.getSource().get("price")+"  "+hit.getSource().get("goodsAttr")+"  "+hit.getSource().get("userId"));
	       //  System.out.println(hit.getSourceAsString());
	       }
	}
	
	
     public static void createMapping() throws Exception {
    	 XContentBuilder builder=XContentFactory.jsonBuilder()
    			 .startObject()
    			 .startObject("job_log")
    			 .startObject("properties")
    			 .startObject("host").field("type", "string").field("store", "true").field("index","analyzed").endObject()
    			 .startObject("jobName").field("type", "string").field("store", "yes").field("analyzer","ik").field("search_analyzer", "ik").endObject()
    			 .startObject("jobGroup").field("type", "string").field("store", "yes").field("analyzer", "ik").field("search_analyzer", "ik").endObject()
    			 .endObject()
    			 .endObject()
    			 .endObject();
    			 PutMappingRequest mapping = Requests.putMappingRequest("logs").type("job_log").source(builder);
    			 Client client = ElasticSearchUtil.getClient();
    			 client.admin().indices().putMapping(mapping).actionGet();
    			 client.close();
     }

	
}
